From c5736a30da185d639f3feb05b6933938aed42fb8 Mon Sep 17 00:00:00 2001 From: Paul Donald Date: Tue, 8 Jul 2025 01:32:39 +0200 Subject: [PATCH] luci-app-chrony: allow non NTS variant also Closes #7857 Signed-off-by: Paul Donald --- applications/luci-app-chrony/Makefile | 2 +- .../luci-static/resources/view/chrony.js | 61 ++++++++++++------- .../usr/share/rpcd/acl.d/luci-app-chrony.json | 3 + 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/applications/luci-app-chrony/Makefile b/applications/luci-app-chrony/Makefile index 115421529e..22839a2161 100644 --- a/applications/luci-app-chrony/Makefile +++ b/applications/luci-app-chrony/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk LUCI_TITLE:=LuCI support for chrony -LUCI_DEPENDS:=+luci-base +chrony-nts +LUCI_DEPENDS:=+luci-base +chrony PKG_LICENSE:=Apache-2.0 diff --git a/applications/luci-app-chrony/htdocs/luci-static/resources/view/chrony.js b/applications/luci-app-chrony/htdocs/luci-static/resources/view/chrony.js index 4dcb1525bf..fbd123ec8c 100644 --- a/applications/luci-app-chrony/htdocs/luci-static/resources/view/chrony.js +++ b/applications/luci-app-chrony/htdocs/luci-static/resources/view/chrony.js @@ -7,7 +7,18 @@ return view.extend({ - render(data) { + load() { + return fs.exec_direct('/usr/sbin/chronyd', ['-v']).then(output => { + const flags = ['IPv6', 'NTP', 'NTS', 'RTC']; + const features = Object.fromEntries( + flags.map(flag => [flag.toLowerCase(), output.includes(`+${flag}`)]) + ); + + return features; + }); + }, + + render(features) { const docUrl = 'https://chrony-project.org/documentation.html'; let m, s, o; @@ -28,22 +39,24 @@ return view.extend({ o.nocreate = true; o.rmempty = false; - // NTS - s = m.section(form.NamedSection, 'nts', 'nts', _('Network Time Security (NTS)')); - s.anonymous = true; - s.addremove = true; + if (features.nts) { + // NTS + s = m.section(form.NamedSection, 'nts', 'nts', _('Network Time Security (NTS)')); + s.anonymous = true; + s.addremove = true; - o = s.option(form.Flag, 'rtccheck', _('RTC Check'), - _('Check for the presence of %s.'.format('/dev/rtc0'), 'Check for RTC character device') + '
' + - _('Disables certificate time checks via %s if RTC is absent.'.format('nocerttimecheck') ) ); - o.default = o.disabled; + o = s.option(form.Flag, 'rtccheck', _('RTC Check'), + _('Check for the presence of %s.'.format('/dev/rtc0'), 'Check for RTC character device') + '
' + + _('Disables certificate time checks via %s if RTC is absent.'.format('nocerttimecheck') ) ); + o.default = o.disabled; - o = s.option(form.Flag, 'systemcerts', _('Use system CA bundle')); - o.default = o.enabled; + o = s.option(form.Flag, 'systemcerts', _('Use system CA bundle')); + o.default = o.enabled; - o = s.option(form.FileUpload, 'trustedcerts', _('Trusted certificates')); - o.optional = true; - o.root_directory = '/etc'; + o = s.option(form.FileUpload, 'trustedcerts', _('Trusted certificates')); + o.optional = true; + o.root_directory = '/etc'; + } // Stepping s = m.section(form.NamedSection, 'makestep', 'makestep', _('Stepping'), @@ -120,7 +133,7 @@ return view.extend({ _('Remote NTP servers for your chronyd')); s.anonymous = true; s.addremove = true; - insertTypedSectionOptions(m, s, o, 'server'); + insertTypedSectionOptions(m, s, o, 'server', features); // Pool entries s = m.section(form.TypedSection, 'pool', _('Pool'), @@ -128,7 +141,7 @@ return view.extend({ _('The pool name is expected to resolve to multiple addresses which might change over time.')); s.anonymous = true; s.addremove = true; - insertTypedSectionOptions(m, s, o, 'pool'); + insertTypedSectionOptions(m, s, o, 'pool', features); // Peer entries s = m.section(form.TypedSection, 'peer', _('Peer'), @@ -136,20 +149,20 @@ return view.extend({ _('A single symmetric association allows the peers to be both servers and clients to each other.')); s.anonymous = true; s.addremove = true; - insertTypedSectionOptions(m, s, o, 'peer'); + insertTypedSectionOptions(m, s, o, 'peer', features); // Servers assigned (to us) via DHCP s = m.section(form.NamedSection, 'dhcp_ntp_server', 'dhcp_ntp_server', _('DHCP(v6)'), _('Options for servers provided to this host via DHCP(v6) (via the WAN for example).')); s.anonymous = true; - insertTypedSectionOptions(m, s, o, 'dhcp_ntp_server'); + insertTypedSectionOptions(m, s, o, 'dhcp_ntp_server', features); return m.render(); } }); -function insertTypedSectionOptions(m, s, o, type) { +function insertTypedSectionOptions(m, s, o, type, features) { o = s.option(form.Flag, 'disabled', _('Disabled')); o.default = o.disabled; // disabled default is disabled i.e., enabled @@ -166,10 +179,12 @@ function insertTypedSectionOptions(m, s, o, type) { o.default = o.disabled o.depends('disabled', '0'); - o = s.option(form.Flag, 'nts', _('NTS')); - o.rmempty = true; - o.default = o.disabled - o.depends('disabled', '0'); + if (features.nts) { + o = s.option(form.Flag, 'nts', _('NTS')); + o.rmempty = true; + o.default = o.disabled + o.depends('disabled', '0'); + } } o = s.option(form.Flag, 'prefer', _('Prefer')); diff --git a/applications/luci-app-chrony/root/usr/share/rpcd/acl.d/luci-app-chrony.json b/applications/luci-app-chrony/root/usr/share/rpcd/acl.d/luci-app-chrony.json index 397f18f231..637f7c6ce2 100644 --- a/applications/luci-app-chrony/root/usr/share/rpcd/acl.d/luci-app-chrony.json +++ b/applications/luci-app-chrony/root/usr/share/rpcd/acl.d/luci-app-chrony.json @@ -2,6 +2,9 @@ "luci-app-chrony": { "description": "Grant UCI access for luci-app-chrony", "read": { + "file": { + "/usr/sbin/chronyd -v" : [ "exec" ] + }, "uci": [ "chrony" ] }, "write": { -- 2.30.2